#include <rtthread.h>
#include "bsp_usart.h"

#define RT_USING_USART

#ifdef RT_USING_USART

// #ifdef RT_USING_DEVICE
// #include <rtdevice.h>
// #endif


typedef struct
{
    struct rt_device parent;
    USART_TypeDef *usart_base;
    IRQn_Type usart_irq;
    rt_uint8_t dat;
    rt_uint8_t length;
} STM32_USART_Typedef;

STM32_USART_Typedef USART1_Device=
{
    .length=0,
}; //一般只使用串口1

void usart_irq_handler(STM32_USART_Typedef *usart)
{
    /* enter interrupt */
    rt_interrupt_enter(); //添加中断锁
    if (USART_GetITStatus(usart->usart_base, USART_IT_RXNE) == SET)
    {
        USART1_Device.dat = (rt_uint8_t)USART_ReceiveData(usart->usart_base);
        USART1_Device.length=1;
        if (usart->parent.rx_indicate != RT_NULL)
        { //这里其实就是释放信号量
            usart->parent.rx_indicate(&usart->parent, 1);
        }
    }
        USART_ClearITPendingBit(usart->usart_base, USART_IT_RXNE);
    /* leave interrupt */
    rt_interrupt_leave();
}

/**
  * @brief  USART1串口中断服务函数
  * @param  None	
  * @retval None
  */
void DEBUG_USART_IRQHandler(void)
{
    usart_irq_handler(&USART1_Device);
}

/**
  * @brief  USART串口中断向量配置函数
  * @param  None	
  * @retval None
  */
static void NVIC_Configuration(STM32_USART_Typedef *usart) //静态函数仅供本文件调用
{
    NVIC_InitTypeDef NVIC_InitStruct; //初始化NVIC结构体
    //最重要的是要分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置优先级组  (各占两位)

    NVIC_InitStruct.NVIC_IRQChannel = usart->usart_irq;    //中断号
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级1级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;        //子优先级
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;           //使能中断
    NVIC_Init(&NVIC_InitStruct);                           //执行初始化
}

/**
  * @brief  USART初始化函数
  * @param  None	
  * @retval None
  */
static void USART_Config(STM32_USART_Typedef *usart)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;

    //开启相关外设的时钟
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);           //开启USART1的时钟
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE); //开启GPIO的时钟

    //配置USART的相应管脚的模式
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //Tx管脚
    GPIO_InitStruct.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //Rx管脚
    GPIO_InitStruct.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStruct);

    //配置串口的工作参数   即波特率=115200   数据长度=8bit    停止位=1bit   校验位=无  硬件流控制=无
    USART_InitStruct.USART_BaudRate = DEBUG_USART_BAUDRATE;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //配置模式(收发一起)
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;

    USART_Init(usart->usart_base, &USART_InitStruct); //DEBUG_USARTx一个结构体指针

    //开启USART中断
    NVIC_Configuration(usart);

    //USART串口中断下面，还得开启一些中断
    USART_ITConfig(usart->usart_base, USART_IT_RXNE, ENABLE); //接收完成中断 (有好几个中断,都可引起USART中断)

    //使能USART
    USART_Cmd(usart->usart_base, ENABLE);
}

/**
  * @brief  给RTT调用的串口初始化函数(这里只使用USART1)
  * @param  dev:指向待初始化的设备   	
  * @retval None
  */
static rt_err_t rt_uart_init(rt_device_t dev)
{
    STM32_USART_Typedef *usart;

    RT_ASSERT(dev != RT_NULL);
    usart = (STM32_USART_Typedef *)dev; ////
    USART_Config(usart);
    return RT_EOK;
}

/**
  * @brief  串口设备打开函数
  * @param  dev:指向待打开的设备   
  * @param  flag:标志位???	
  * @retval None
  */
static rt_err_t rt_uart_open(rt_device_t dev, rt_uint16_t flag)
{
    STM32_USART_Typedef *usart;

    RT_ASSERT(dev != RT_NULL);
    usart = (STM32_USART_Typedef *)dev; ////

    if (dev->flag & RT_DEVICE_FLAG_INT_RX)
    {
        NVIC_EnableIRQ(usart->usart_irq);
    }
    return RT_EOK;
}

/**
  * @brief  串口设备关闭函数
  * @param  dev:指向待关闭的设备   
  * @param  flag:标志位???	
  * @retval None
  */
static rt_err_t rt_uart_close(rt_device_t dev)
{
    STM32_USART_Typedef *usart;

    RT_ASSERT(dev != RT_NULL);
    usart = (STM32_USART_Typedef *)dev; ////

    if (dev->flag & RT_DEVICE_FLAG_INT_RX)
    {
        NVIC_DisableIRQ(usart->usart_irq); //core_cm3.h中有
    }
    return RT_EOK;
}

static rt_size_t rt_uart_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    rt_size_t length=0;
    STM32_USART_Typedef *usart;
    RT_ASSERT(serial != RT_NULL);
    usart = (STM32_USART_Typedef *)dev; ////

    rt_base_t level;
    RT_ASSERT(usart != RT_NULL);
    level = rt_hw_interrupt_disable();
    ((rt_uint8_t *)buffer)[0] = usart->dat;
    length=usart->length;
    usart->length=0;
    rt_hw_interrupt_enable(level);
    return length;
}

static rt_size_t rt_uart_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    //这里固定为USART1
    char *ptr = (char *)buffer;
    STM32_USART_Typedef *uart;
    RT_ASSERT(serial != RT_NULL);
    uart = (STM32_USART_Typedef *)dev; ////
    if (dev->open_flag & RT_DEVICE_FLAG_STREAM)
    {
        /* stream mode */
        while (size)
        {
            if (*ptr == '\n')
            {
                while (USART_GetFlagStatus(uart->usart_base, USART_FLAG_TXE) == RESET)
                {
                    ;
                }
                USART_ClearFlag(uart->usart_base, USART_FLAG_TXE);
                USART_SendData(uart->usart_base, '\r');
            }
            while (USART_GetFlagStatus(uart->usart_base, USART_FLAG_TXE) == RESET)
            {
                ;
            }
            USART_ClearFlag(uart->usart_base, USART_FLAG_TXE);
            USART_SendData(uart->usart_base, *ptr);

            ptr++;
            size--;
        }
    }
    else
    {
        while (size)
        {
            while (USART_GetFlagStatus(uart->usart_base, USART_FLAG_TXE) == RESET)
            {
                ;
            }
            USART_ClearFlag(uart->usart_base, USART_FLAG_TXE);
            USART_SendData(uart->usart_base, *ptr);
            ptr++;
            size--;
        }
    }

    return (rt_size_t)ptr - (rt_size_t)buffer;
}

int rt_hw_usart_init(void)
{
    STM32_USART_Typedef *uart;

    uart = &USART1_Device;

    uart->parent.type = RT_Device_Class_Char;
    uart->usart_base = DEBUG_USARTx;
    uart->usart_irq = DEBUG_USART_IRQ;

    uart->parent.init = rt_uart_init;
    uart->parent.open = rt_uart_open;
    uart->parent.close = rt_uart_close;
    uart->parent.read = rt_uart_read;
    uart->parent.write = rt_uart_write;
    uart->parent.control = RT_NULL;
    uart->parent.user_data = RT_NULL;
    rt_device_register(&uart->parent, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
    return 0;
}
INIT_BOARD_EXPORT(rt_hw_usart_init);

//发送一个字符
void USART_SendByte(USART_TypeDef *USARTx, uint8_t ch)
{
    USART_SendData(USARTx, ch);
    //下面就是等待发送完成       //TXE发送寄存器为空(但移位寄存器可能并不为空)，发送单个字节的时候使用
    while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET)
        ;
}
//下面得重写一些标准的C库函数(需要重写前面包含stdio.h吗)

//重定向c库函数printf到串口，重定向后可使用printf函数
int	fputc(int ch,FILE *f)    //这里的FILE *f其实没什么屌用
{
    USART_SendByte(DEBUG_USARTx,(uint8_t)ch);
    while(USART_GetFlagStatus  (DEBUG_USARTx,USART_FLAG_TXE)==RESET);  //等待发送完成
    return	ch;   //按标准返回
}

//重定向c库函数scanf到串口,重定向后可使用scanf,getchar等函数
int	fgetc(FILE	*f)
{
    while(USART_GetFlagStatus  (DEBUG_USARTx,USART_FLAG_RXNE)==RESET);
    return USART_ReceiveData  (DEBUG_USARTx);
}

#endif /*RT_USING_USART*/
